1 /****************************** Module Header ******************************\
2 * Module Name: Solution2.cpp
3 * Project: CppAutomateVisio
4 * Copyright (c) Microsoft Corporation.
6 * The code in Solution2.h/cpp demontrates the use of C/C++ and the COM APIs
7 * to automate Visio. The raw automation is much more difficult, but it is
8 * sometimes necessary to avoid the overhead with MFC, or problems with
9 * #import. Basically, you work with such APIs as CoCreateInstance(), and COM
10 * interfaces such as IDispatch and IUnknown.
12 * This source is subject to the Microsoft Public License.
13 * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
14 * All other rights reserved.
16 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
17 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
19 \***************************************************************************/
21 #pragma region Includes
23 #include "Solution2.h"
27 DWORD WINAPI
AutomateVisioByCOMAPI(LPVOID lpParam
)
31 // Initializes the COM library on the current thread and identifies
32 // the concurrency model as single-thread apartment (STA).
33 // [-or-] ::CoInitialize(NULL);
34 // [-or-] ::CoCreateInstance(NULL);
35 ::CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
38 /////////////////////////////////////////////////////////////////////////
39 // Create the Visio.Application COM object using C++ and COM APIs.
42 // Get CLSID of the server
46 // Option 1. Get CLSID from ProgID using CLSIDFromProgID.
47 LPCOLESTR progID
= L
"Visio.Application";
48 hr
= ::CLSIDFromProgID(progID
, &clsid
);
51 wprintf(L
"CLSIDFromProgID(\"%s\") failed w/err 0x%08lx\n", progID
, hr
);
54 // Option 2. Build the CLSID directly.
55 /*const IID CLSID_Application =
56 {0x00021A20,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
57 clsid = CLSID_Application;*/
59 // Start the server and get the IDispatch interface
61 IDispatch
* pVisioApp
= NULL
;
62 hr
= CoCreateInstance( // [-or-] CoCreateInstanceEx, CoGetObject
63 clsid
, // CLSID of the server
65 CLSCTX_LOCAL_SERVER
, // Visio.Application is a local server
66 IID_IDispatch
, // Query the IDispatch interface
67 (void **)&pVisioApp
); // Output
71 _tprintf(_T("Visio is not registered properly w/err 0x%08lx\n"),
76 _putts(_T("Visio.Application is started"));
79 /////////////////////////////////////////////////////////////////////////
80 // Make Visio invisible. (Application.Visible = 0)
87 hr
= AutoWrap(DISPATCH_PROPERTYPUT
, NULL
, pVisioApp
, L
"Visible", 1, x
);
91 /////////////////////////////////////////////////////////////////////////
92 // Create a new Document based on no template.
93 // (i.e. Application.Documents.Add(""))
96 // Get the Documents collection
97 IDispatch
* pDocs
= NULL
;
100 VariantInit(&result
);
101 hr
= AutoWrap(DISPATCH_PROPERTYGET
, &result
, pVisioApp
, L
"Documents", 0);
102 pDocs
= result
.pdispVal
;
105 // Call Documents.Add("") to get a new document based on no template
106 IDispatch
* pDoc
= NULL
;
110 x
.bstrVal
= ::SysAllocString(L
"");
113 VariantInit(&result
);
114 hr
= AutoWrap(DISPATCH_METHOD
, &result
, pDocs
, L
"Add", 1, x
);
115 pDoc
= result
.pdispVal
;
120 _putts(_T("A new document is created"));
123 /////////////////////////////////////////////////////////////////////////
124 // Draw a rectangle and a oval on the first page.
127 _putts(_T("Draw a rectangle and a oval"));
129 // Get the Pages collection
130 IDispatch
* pPages
= NULL
;
133 VariantInit(&result
);
134 hr
= AutoWrap(DISPATCH_PROPERTYGET
, &result
, pDoc
, L
"Pages", 0);
135 pPages
= result
.pdispVal
;
138 // Get the first page (pPages->Item[1])
139 IDispatch
* pPage
= NULL
;
146 VariantInit(&result
);
147 hr
= AutoWrap(DISPATCH_PROPERTYGET
, &result
, pPages
, L
"Item", 1, x
);
148 pPage
= result
.pdispVal
;
151 // Draw a rectangle (pPage->DrawRectangle)
152 IDispatch
* pRectShape
= NULL
;
168 VariantInit(&result
);
169 hr
= AutoWrap(DISPATCH_METHOD
, &result
, pPage
, L
"DrawRectangle",
171 pRectShape
= result
.pdispVal
;
174 // Draw a oval (pPage->DrawOval)
175 IDispatch
* pOvalShape
= NULL
;
191 VariantInit(&result
);
192 hr
= AutoWrap(DISPATCH_METHOD
, &result
, pPage
, L
"DrawOval",
194 pOvalShape
= result
.pdispVal
;
198 /////////////////////////////////////////////////////////////////////
199 // Save the document as a vsd file and close it.
202 _putts(_T("Save and close the document"));
206 // Make the file name
208 // Get the directory of the current exe.
209 WCHAR szFileName
[MAX_PATH
];
210 if (FAILED(GetModuleDirectoryW(szFileName
, MAX_PATH
)))
212 _putts(_T("GetModuleDirectoryW failed"));
216 // Concat "Sample2.vsd" to the directory
217 wcsncat_s(szFileName
, MAX_PATH
, L
"Sample2.vsd", 11);
219 // Convert the NULL-terminated string to BSTR
221 vtFileName
.vt
= VT_BSTR
;
222 vtFileName
.bstrVal
= ::SysAllocString(szFileName
);
224 hr
= AutoWrap(DISPATCH_METHOD
, NULL
, pDoc
, L
"SaveAs", 1, vtFileName
);
226 VariantClear(&vtFileName
);
230 hr
= AutoWrap(DISPATCH_METHOD
, NULL
, pDoc
, L
"Close", 0);
233 /////////////////////////////////////////////////////////////////////////
234 // Quit the Visio application. (i.e. Application.Quit())
237 _putts(_T("Quit the Visio application"));
238 hr
= AutoWrap(DISPATCH_METHOD
, NULL
, pVisioApp
, L
"Quit", 0);
241 /////////////////////////////////////////////////////////////////////////
242 // Release the COM objects.
245 if (pOvalShape
!= NULL
)
247 pOvalShape
->Release();
249 if (pRectShape
!= NULL
)
251 pRectShape
->Release();
269 if (pVisioApp
!= NULL
)
271 pVisioApp
->Release();
274 // Uninitialize COM for this thread
283 * The definition of AutoWrap in the header file
286 * Separate Solution2.h | AutoWrap
288 HRESULT
AutoWrap(int autoType
, VARIANT
*pvResult
, IDispatch
*pDisp
,
289 LPOLESTR ptName
, int cArgs
...)
291 // Begin variable-argument list
293 va_start(marker
, cArgs
);
297 _putts(_T("NULL IDispatch passed to AutoWrap()"));
302 DISPPARAMS dp
= { NULL
, NULL
, 0, 0 };
303 DISPID dispidNamed
= DISPID_PROPERTYPUT
;
307 // Get DISPID for name passed
308 hr
= pDisp
->GetIDsOfNames(IID_NULL
, &ptName
, 1, LOCALE_USER_DEFAULT
, &dispID
);
311 wprintf(L
"IDispatch::GetIDsOfNames(\"%s\") failed w/err 0x%08lx\n",
316 // Allocate memory for arguments
317 VARIANT
*pArgs
= new VARIANT
[cArgs
+ 1];
318 // Extract arguments...
319 for(int i
=0; i
< cArgs
; i
++)
321 pArgs
[i
] = va_arg(marker
, VARIANT
);
328 // Handle special-case for property-puts
329 if (autoType
& DISPATCH_PROPERTYPUT
)
332 dp
.rgdispidNamedArgs
= &dispidNamed
;
336 hr
= pDisp
->Invoke(dispID
, IID_NULL
, LOCALE_SYSTEM_DEFAULT
,
337 autoType
, &dp
, pvResult
, NULL
, NULL
);
340 wprintf(L
"IDispatch::Invoke(\"%s\"=%08lx) failed w/err 0x%08lx\n",
345 // End variable-argument section